package org.github.core.logger;

import lombok.val;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import javax.annotation.Nullable;
import org.slf4j.Logger;
import static cn.hutool.core.util.ReflectUtil.getField;
import static cn.hutool.core.util.ReflectUtil.getStaticFieldValue;
import static org.github.core.logger.MethodInvoke.buildInfo;

@Aspect
public class LogInvoke {
    @AfterReturning(value = "pointcut()", returning = "value")
    public void afterReturning(JoinPoint point, @Nullable Object value) {
        Logger log = getLogger(point);
        Log annotation = getAnnotation(point);
        String info = buildInfo(value);
        log.info("【{}】执行结束：{}", annotation.value(), info);
    }

    @AfterThrowing(value = "pointcut()", throwing = "e")
    public void afterThrowing(JoinPoint point, Exception e) {
        Logger log = getLogger(point);
        Log annotation = getAnnotation(point);
        log.error("【{}】发生异常：{}", annotation.value(), e.getMessage());
    }

    @Before("pointcut()")
    public void before(JoinPoint point) {
        Logger log = getLogger(point);
        Log annotation = getAnnotation(point);
        val args = point.getArgs();
        String info = buildInfo(args);
        log.info("【{}】开始执行：{}", annotation.value(), info);
    }

    @Pointcut("@annotation(org.github.core.logger.Log)")
    public void pointcut() {
    }

    private static Logger getLogger(JoinPoint point) {
        val type = point.getTarget().getClass();
        return (Logger) getStaticFieldValue(getField(type, "log"));
    }

    private static Log getAnnotation(JoinPoint point) {
        val sign = (MethodSignature) point.getSignature();
        val method = sign.getMethod();
        return method.getAnnotation(Log.class);
    }
}
